#pragma once

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h>

#define NUM 8

template<typename T>
class RingQueue{
  private:
    std::vector<T> q;
    int capacity;
    int c_pos;
    int p_pos;

    sem_t blank_sem;
    sem_t data_sem;
  private:
    bool IsFull()
    {
      return abs(c_pos - p_pos) + 1 == capacity;
    }
    bool IsEmpty()
    {
      return c_pos == p_pos;
    }
  private:
    void P(sem_t& s)
    {
      sem_wait(&s);  
    }
    void V(sem_t& s)
    {
      sem_post(&s);
    }
  public:
    RingQueue(int _capacity = NUM):capacity(_capacity)
    {
      c_pos = 0;
      p_pos = capacity;
      q.resize(capacity);
      sem_init(&blank_sem, 0, capacity);
      sem_init(&data_sem, 0, 0);
    }
    void Push(const T& in)
    {
      P(blank_sem);

      q[p_pos++] = in;
      p_pos %= capacity;
      V(data_sem);
    }
    void Pop(T& out)
    {
      P(data_sem);

      out = q[c_pos++];
      c_pos %= capacity;
      V(blank_sem);
    }
    ~RingQueue()
    {
      sem_destroy(&blank_sem);
      sem_destroy(&data_sem);
    }
};
